import React, { ChangeEvent, CSSProperties, useEffect, useState } from "react";
import TCheckbox from "@/components/Input/Checkbox";
import "./index.scss";

interface ColumnsTypes<T> {
  title?: React.ReactNode;
  dataIndex?: keyof T;
  width?: number | string;
  align?: "left" | "center" | "right";
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  render?: (value: any, record: T, index: number) => React.ReactNode;
  sorter?: (a: T, b: T) => number; // 排序函数
}
interface rowSelectionTypes<T> {
  selectedRowKeys?: Array<number | string>;
  defaultSelectedRowKeys?: Array<number | string>;
  // 选项发生变化时的回调
  onChange?: (
    selectedRowKeys: Array<number | string>,
    selectedRows: T[],
    info: { type: "checkbox" | "radio" }
  ) => void;
  // 手动选择|取消时的回调
  onSelect?: (
    record: T,
    selected: boolean,
    selectedRows: T[],
    nativeEvent: ChangeEvent<HTMLInputElement>
  ) => void;
  onSelectAll?: (selected: boolean, selectedRows: T[], changeRows: T[]) => void;
}
interface TableProps<T> {
  data: T[];
  columns: ColumnsTypes<T>[];
  rowKey?: keyof T | ((record: T) => number | string);
  width?: string | number;
  style?: CSSProperties;
  checkbox?: boolean;
  rowSelection?: rowSelectionTypes<T>;
}

export type TableColumnsType<T> = ColumnsTypes<T>[];
export type KeyType<T> = Exclude<keyof T, symbol> | string | number;

function TTable<T>(props: TableProps<T>) {
  const {
    data,
    columns,
    rowKey,
    width,
    style,
    checkbox,
    rowSelection = {},
  } = props;
  const {
    selectedRowKeys = [],
    defaultSelectedRowKeys = [],
    onChange,
    onSelect,
    onSelectAll,
  } = rowSelection;

  const isControlled = "selectedRowKeys" in rowSelection;

  // 组件内部维护的选中keys的状态
  const [innerSelectedRowKeys, setInnerSelectedRowKeys] = useState<
    KeyType<T>[]
  >(isControlled ? selectedRowKeys : defaultSelectedRowKeys);

  // 受控模式同步逻辑
  useEffect(() => {
    // 受控模式受限于父组件的状态，所以每次组件更新都要使用父组件状态来更新内部状态
    if (isControlled) {
      setInnerSelectedRowKeys(selectedRowKeys);
    }
  }, [selectedRowKeys, isControlled]);

  function getRowKey(record: T, index: number) {
    if (rowKey) {
      if (typeof rowKey === "function") {
        return rowKey(record);
      }

      const value = record[rowKey];

      if (typeof value !== "string" && typeof value !== "number") {
        console.error(
          `rowKey "${String(rowKey)}" 对应的值必须是 string 或 number 类型 `
        );
        return index;
      }
      return value;
    }
    return index;
  }

  function handleSelectAll(e: ChangeEvent<HTMLInputElement>) {
    const checked = e.target.checked;

    const newSelectKeys = checked ? data.map((d, i) => getRowKey(d, i)) : [];
    const newSelectRows = checked ? data : [];
    const changeSelectRows = data.filter(
      (d, i) => checked !== innerSelectedRowKeys.includes(getRowKey(d, i))
    );
    // 非受控模式，直接更新内部状态
    if (!isControlled) {
      setInnerSelectedRowKeys(newSelectKeys);
    }
    onChange?.(newSelectKeys, newSelectRows, {
      type: "checkbox",
    });
    onSelectAll?.(checked, newSelectRows, changeSelectRows);
  }

  function handleChange(
    e: ChangeEvent<HTMLInputElement>,
    record: T,
    key: KeyType<T>
  ) {
    const checked = e.target.checked;

    const currentKeys = isControlled ? selectedRowKeys : innerSelectedRowKeys;

    const newSelectKeys = checked
      ? [...currentKeys, key]
      : currentKeys.filter((k) => k !== key);

    const newSelectRows = data.filter((d, i) =>
      newSelectKeys.includes(getRowKey(d, i))
    );
    // 非受控模式直接处理内部状态
    if (!isControlled) {
      setInnerSelectedRowKeys(newSelectKeys);
    }
    onChange?.(newSelectKeys, newSelectRows, {
      type: "checkbox",
    });
    onSelect?.(record, checked, newSelectRows, e);
  }

  function renderCheckbox(record: T, key: KeyType<T>) {
    return (
      <TCheckbox
        onChange={(e) => handleChange(e, record, key)}
        checked={
          isControlled
            ? selectedRowKeys.includes(key)
            : innerSelectedRowKeys.includes(key)
        }
      />
    );
  }
  // 全选框逻辑判断
  const allChecked =
    data.length > 0 &&
    (isControlled
      ? (rowSelection.selectedRowKeys || []).length === data.length
      : innerSelectedRowKeys.length === data.length);

  return (
    <>
      <table className="t-table" style={{ ...style, width }}>
        <thead>
          <tr>
            {checkbox && (
              <th>
                <TCheckbox onChange={handleSelectAll} checked={allChecked} />
              </th>
            )}
            {columns.map((col, index) => {
              return <th key={index}>{col.title}</th>;
            })}
          </tr>
        </thead>
        <tbody>
          {data.map((record, dataIndex) => {
            const key = getRowKey(record, dataIndex);
            return (
              <tr key={key}>
                {checkbox && <td>{renderCheckbox(record, key)}</td>}
                {columns.map((col, colIndex) => {
                  if (col.render) {
                    const value = col.dataIndex
                      ? record[col.dataIndex]
                      : undefined;
                    return (
                      <td key={colIndex}>
                        {col.render(value, record, colIndex)}
                      </td>
                    );
                  } else if (col.dataIndex) {
                    return (
                      <td key={colIndex}>
                        {/* 不使用类型断言会报类型错误 */}
                        {record[col.dataIndex] as React.ReactNode}
                      </td>
                    );
                  }
                  return <td key={colIndex}></td>;
                })}
              </tr>
            );
          })}
        </tbody>
      </table>
    </>
  );
}

export default TTable;
